﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Sql;

namespace sgsBase
{
    public enum SecLevel {Hidden, Visible, Enabled};
	/// <summary>
	/// Security Item containing all information regarding the security on something
	/// </summary>
	/// 
    [Serializable]
    public class SecItem
    {
		private DbSecItem m_dbsecitem = new DbSecItem();

        public SecLevel Level = SecLevel.Hidden;

		private string[] nameparts;

		public string Name
		{
			get
			{
				return m_dbsecitem.ItemName;
			}
			set
			{
				m_dbsecitem.ItemName = value;
				m_dbsecitem.Select();
			}
		}

		public int Id
		{
			get
			{
				return m_dbsecitem.ItemId;
			}
		}

		// security string can be broken down into smaller pieces:
		// Area.Section.Group.Item
		public string Area
		{
			get { return part(0); }
		}
		public string Section
		{
			get	{ return part(1); }
		}
		public string Group
		{
			get { return part(2); }
		}
		public string Item
		{
			get { return part(3); }
		}

        public SecItem(string name, SecLevel level)
        {
            Name = name;
            Level = level;
			nameparts = name.Split('.');
        }

		public SecItem(string name, SecLevel level, int id, string descr)
		{
			m_dbsecitem.ItemName = name;
			Level = level;
			m_dbsecitem.ItemId = id;
			m_dbsecitem.Descr = descr;
			nameparts = name.Split('.');
		}
		/// <summary>
		/// return the part of the name searched for
		/// </summary>
		/// <param name="i"></param>
		/// <returns></returns>
		/// Checks to see if a name was given. if so, if the length of the pieces is good, 
		/// then return the asked-for part. If not, return the last element of the array.
		private string part(int i)
		{
			if (nameparts == null)
				return "";

			if (nameparts.Length > i)
				return nameparts[i];

			if (nameparts.Length > 0)
				return nameparts[nameparts.Length - 1];

			return "";
		}

		public DataRow asRow(DataTable dt)
		{
			DataRow dr;
			dr = dt.NewRow();
			dr["ItemId"]    = Id.ToString();
			dr["ItemName"]  = Name;
			dr["ItemDesc"]  = m_dbsecitem.Descr;
			dr["ItemLevel"] = Level.ToString();
			dr["Area"]    = Area;
			dr["Section"] = Section;
			dr["Group"]   = Group;
			dr["Item"]    = Item;

			return dr;
		}

		public static DataTable asTable()
		{
			DataTable dt = new DataTable();

			Type stringtype = Type.GetType("System.String");

			dt.Columns.Add(new DataColumn("ItemId", stringtype));
			dt.Columns.Add(new DataColumn("ItemName", stringtype));
			dt.Columns.Add(new DataColumn("ItemDesc", stringtype));
			dt.Columns.Add(new DataColumn("ItemLevel", stringtype));
			dt.Columns.Add(new DataColumn("Area", stringtype));
			dt.Columns.Add(new DataColumn("Section", stringtype));
			dt.Columns.Add(new DataColumn("Group", stringtype));
			dt.Columns.Add(new DataColumn("Item", stringtype));

			return dt;
		}

	}
	/// <summary>
	/// Group with security item levels
	/// </summary>
	/// typically created based on the group ID or group Name
    [Serializable]
    public class SecGroup
	{
		private DbSecGroup m_secgroup = new DbSecGroup();
		private List<SecItem> m_secitems = new List<SecItem>();

		public SecGroup(int GroupId)
		{
			m_secgroup.GroupId = GroupId;
			m_secgroup.Select();
		}

		public SecGroup(string GroupName)
		{
			m_secgroup.GroupName = GroupName;
			m_secgroup.Select();
		}
	}

	/// <summary>
	/// Security for thcStore items.
	/// </summary>
    [Serializable]
    public class SgsSecurity
    {
        private SgsUser m_user;
        private List<SecItem> m_secitems;

		public virtual SgsUser User
		{
			get
			{
				return m_user;
			}
			set
			{
				m_user = value;
                Reset();
			}
		}

		public virtual int UserId
		{
			get { return User.ID; }
		}

		public int UserGroup
		{
			get
			{
				DbVwSecXrGroupUser dxgu = new DbVwSecXrGroupUser();

				dxgu.UserId = m_user.ID;
				dxgu.GroupType = 0;
				if (dxgu.Select())
					return dxgu.GroupId;

				// no security group has been created yet. It needs to be, so do it here.
				m_user.NewUserSecurity(m_user.LoginName);
				dxgu.ClearValues();
				dxgu.UserId = m_user.ID;
				dxgu.GroupType = 0;
				if (dxgu.Select())
					return dxgu.GroupId;

				//blah what if it didnt work again? not sure.
				return 0;
			}
		}

		public SgsSecurity(SgsUser user)
        {
            User = user;
            Reset();
        }
		protected SgsSecurity()
		{
		}

        public void Reset()
        {
            m_secitems = new List<SecItem>();
        }

		/// <summary>
		/// Get the permission level for the given security item. 
		/// </summary>
		/// <param name="SecurityItem">Name of the security item being checked.</param>
		/// <returns>Level of Security for the given user for the item</returns>
		public SecLevel GetPermission(string Area, string Section)
		{
			return GetPermission(Area + "." + Section);
		}
		public SecLevel GetPermission(string Area, string Section, string Group)
		{
			return GetPermission(Area + "." + Section + "." + Group);
		}
		public SecLevel GetPermission(string Area, string Section, string Group, string Item)
		{
			return GetPermission(Area + "." + Section + "." + Group + "." + Item);
		}
        public SecLevel GetPermission(string SecurityItem)
        {
            SecLevel ret = SecLevel.Hidden;

			SecItem seclvl = m_secitems.Find(delegate(SecItem tsl)
            {
                return tsl.Name == SecurityItem;
            });

            if (seclvl != null)
                return seclvl.Level;

			ret = CheckDBLevel(UserId, SecurityItem);

            seclvl = new SecItem(SecurityItem, ret);
            m_secitems.Add(seclvl);

            return ret;
        }

		private SecLevel CheckDBLevel(int UserId, string secItem)
		{
			SecLevel ret = SecLevel.Hidden;

			DbInterface dbi = new DbInterface();

			dbi.SpNew("spSecItemLevel");
			dbi.SpAddParam("user_id", SqlDbType.Int, UserId);
			dbi.SpAddParam("item_name", SqlDbType.VarChar, secItem);

			DataTable dt = dbi.SpRun();

			if (dt.Rows.Count > 0)
			{
				int levelid = Convert.ToInt32(dt.Rows[0][0]);

				if (levelid == 1)
					ret = SecLevel.Visible;
				if (levelid == 2)
					ret = SecLevel.Enabled;
			}
			return ret;
		}

		public int GetId(string SecurityItem)
		{
			SecItem seclvl = m_secitems.Find(delegate(SecItem tsl)
			{
				return tsl.Name == SecurityItem;
			});

			if (seclvl != null)
				return seclvl.Id;

			DbSecItem dsi = new DbSecItem();

			dsi.ItemName = SecurityItem;
			if (dsi.Select())
				return dsi.ItemId;

			return 0;
		}
		public void SetUserPermission(string SecurityItem, SecLevel Security)
		{
			SetUserPermission(SecurityItem, Security, true);
		}
		public void SetUserPermission(string SecurityItem, SecLevel Security, bool Persistent)
		{
			if (UserGroup == 0) // no group for the user exists. This should not happen
				return;
			// if the permission change is persistent (cross sessions), go ahead and update the user's specific group

			if (Persistent)
			{
				// before just inserting it, can we delete it and see what that sets the security to? if it goes back to group, 
				// then this will be a good thing. 
				// first delete any user specific level.
				// next, check if the user now has the correct privileges.
				// if not, add in specific privilege to group.
				DbSecXrGroupItem dxgi = new DbSecXrGroupItem();
				dxgi.GroupId = UserGroup;
				dxgi.ItemId = GetId(SecurityItem);
				dxgi.Delete();

				SecLevel sl = CheckDBLevel(UserId, SecurityItem);

				if (sl != Security)
				{
					dxgi.LevelId = Security.GetHashCode();
					dxgi.InsertUpdate();
				}
			}
			// find security item in memory list. if not there, add it, especially since it may not be persistent.
			SecItem seclvl = m_secitems.Find(delegate(SecItem tsl)
			{
				return tsl.Name == SecurityItem;
			});

			if (seclvl != null)
				seclvl.Level = Security;
			else
			{
				seclvl = new SecItem(SecurityItem, Security);
				m_secitems.Add(seclvl);
			}
		}

		public void Clear()
		{
			m_secitems.Clear();
		}
    }
}
